import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common';
import { RegisterUserDto } from 'src/dto/RegisterUser.dto';
import { PrismaService } from 'src/prisma/prisma.service';
import { RedisService } from 'src/redis/redis.service';
import { md5 } from 'src/utils';
import { User } from 'src/entity/User.entity';
import { LoginDto } from 'src/dto/Login.dto';
import { LoginVo } from 'src/vo/Login.vo';
import { UpdateUserPasswordDto } from 'src/dto/UpdateUserPasswordDto .dto';
import { RedisPrefix } from 'src/enum';
import { UpdateUserDto } from 'src/dto/UpdateUserDto.dto';
import { PaginationService } from 'src/hooks/usePagination';

@Injectable()
export class UserService {
  @Inject(PrismaService)
  private prisma: PrismaService;

  @Inject(RedisService)
  private redis: RedisService;

  @Inject(PaginationService)
  private readonly paginationService: PaginationService;

  validateCaptcha(orgCap, myCap) {
    if (!orgCap) {
      throw new HttpException('验证码已失效', HttpStatus.BAD_REQUEST);
    }
    if (orgCap !== myCap) {
      throw new HttpException('验证码不正确', HttpStatus.BAD_REQUEST);
    }
  }

  async findUserById(id: number) {
    const userInfo = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });
    const { roles, permissions } = await this.findRoleAndPermissionById(id);

    return {
      id: userInfo.id,
      username: userInfo.username,
      nickname: userInfo.nick_name,
      email: userInfo.email,
      phone: userInfo.phone,
      headPic: userInfo.head_pic,
      isFrozen: userInfo.is_frozen,
      roles,
      permissions,
    };
  }

  async register(user: RegisterUserDto) {
    const captcha = await this.redis.get(
      `${RedisPrefix.REGISTER}_${user.email}`,
    );
    this.validateCaptcha(captcha, user.captcha);

    const foundUser = await this.prisma.user.findUnique({
      where: {
        username: user.username,
      },
    });

    if (foundUser) {
      throw new HttpException('用户已存在', HttpStatus.BAD_REQUEST);
    }

    const newUser = new User();
    newUser.username = user.username;
    newUser.password = md5(user.password);
    newUser.email = user.email;
    newUser.nick_name = user.nickname;

    try {
      await this.prisma.user.create({
        data: newUser,
      });
    } catch (e) {
      return '注册失败' + e;
    }
  }

  async findRoleAndPermissionById(id: number) {
    const userWithRole = await this.prisma.userWithRole.findMany({
      where: {
        userId: id,
      },
      include: {
        role: true,
      },
    });
    const roleIds = userWithRole.map((item) => item.roleId);
    const roles = userWithRole.map((item) => item.role.name);

    const roleWithPermission = await this.prisma.roleWithPermission.findMany({
      where: {
        roleId: {
          in: roleIds,
        },
      },
      include: {
        permission: true,
      },
    });

    const permissions = roleWithPermission.map((item) => item.permission.code);
    return {
      roles,
      permissions,
    };
  }

  async login(user: LoginDto) {
    const foundUser = await this.prisma.user.findUnique({
      where: {
        username: user.username,
        is_admin: !!user.isAdmin,
      },
    });

    if (!foundUser) {
      throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
    }

    if (md5(user.password) !== foundUser.password) {
      throw new HttpException('密码错误', HttpStatus.BAD_REQUEST);
    }

    const { roles, permissions } = await this.findRoleAndPermissionById(
      foundUser.id,
    );

    const vo = new LoginVo();
    vo.userInfo = {
      id: foundUser.id,
      username: foundUser.username,
      nickname: foundUser.nick_name,
      email: foundUser.email,
      phone: foundUser.phone,
      headPic: foundUser.head_pic,
      isAdmin: foundUser.is_admin,
      isFrozen: foundUser.is_frozen,
      roles,
      permissions,
    };

    return vo;
  }

  async updatePassword(id: number, passwordDto: UpdateUserPasswordDto) {
    const captcha = await this.redis.get(
      `${RedisPrefix.UPDATE_PASSWORD}_${passwordDto.email}`,
    );
    this.validateCaptcha(captcha, passwordDto.captcha);

    const foundUser = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });

    foundUser.password = md5(passwordDto.password);

    try {
      await this.prisma.user.update({
        where: {
          id,
        },
        data: foundUser,
      });
    } catch (e) {
      return '修改失败' + e;
    }
  }

  async updateInfo(id: number, updateUserDto: UpdateUserDto) {
    const captcha = await this.redis.get(
      `${RedisPrefix.UPDATE_USER}_${updateUserDto.email}`,
    );
    this.validateCaptcha(captcha, updateUserDto.captcha);

    const foundUser = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });

    // 修改头像和昵称
    updateUserDto.nickname && (foundUser.nick_name = updateUserDto.nickname);
    updateUserDto.headPic && (foundUser.head_pic = updateUserDto.headPic);

    try {
      await this.prisma.user.update({
        where: {
          id,
        },
        data: foundUser,
      });
    } catch (e) {
      return '修改失败' + e;
    }
  }

  async freezeUser(id: number) {
    const foundUser = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });

    foundUser.is_frozen = !foundUser.is_frozen;

    try {
      await this.prisma.user.update({
        where: {
          id,
        },
        data: foundUser,
      });
    } catch (e) {
      return '修改失败' + e;
    }
  }

  async getUserList(
    num: number,
    size: number,
    username: string,
    nickname: string,
    email: string,
  ) {
    const query = {
      where: {
        is_admin: false,
        username: {
          contains: username,
        },
        nick_name: {
          contains: nickname,
        },
        email: {
          contains: email,
        },
      },
    };
    return await this.paginationService.paginate('user', query, num, size);
  }
}
